#include "potential_energy.h"

//namespace Config_parameters
//{
//	Opti_alg opti_algo = DIRECT;
//}
namespace Config_parameters
{
	Config_parameters::Opti_alg opti_algo = Config_parameters::DIRECT;
	double Config_parameters::gravity_scale = 1.0;
}
namespace Packing_common
{
	double System_potential_energy::epsilon = 10.0;
	double System_potential_energy::g = 1;
	double System_potential_energy::f = 0.0;
	//double System_potential_energy::t = 2.0;

	Knitro_context::Knitro_context(int nb_vars, int nb_constraits, int nb_nonzero_jac, int nb_nonzero_hess)
		: n(nb_vars), m(nb_constraits), nnzJ(nb_nonzero_jac), nnzH(nb_nonzero_hess)
	{
		lambda = (double*)malloc((m+n) * sizeof(double));
		xLoBnds = (double*)malloc(n * sizeof(double));
		xUpBnds = (double*)malloc(n * sizeof(double));
		xInitials = (double *)malloc(n * sizeof(double));
		if (m == 0)
		{
			cType = 0;
			cLoBnds = cUpBnds = 0;
		}
		else
		{
			cType        = (int*)malloc(m * sizeof(int));
			cLoBnds      = (double*)malloc(m * sizeof(double));
			cUpBnds      = (double*)malloc(m * sizeof(double));
		}
		if (nnzJ == 0)
			jacIndexVars = jacIndexCons = 0;
		else
		{
			jacIndexVars = (int*)malloc(nnzJ * sizeof(int));
			jacIndexCons = (int*)malloc(nnzJ * sizeof(int));
		}
		if (nnzH == 0)
			hessIndexRows = hessIndexCols = 0;
		else
		{
			hessIndexRows = (int*)malloc(nnzH*sizeof(int));
			hessIndexCols = (int*)malloc(nnzH*sizeof(int));
		}
		kc = KTR_new();
		double *p_xInitials = xInitials;
		std::fill(p_xInitials, p_xInitials+n, 0.0);
	}
	Knitro_context::~Knitro_context()
	{
		//std::cout<<"Destructor of Knitro_context starts\n";
		/* free memory (KNITRO maintains its own copy) */
		//free(xLoBnds);	free(xUpBnds); free(xInitials);
		//if(cType) free(cType); 
		//if(cLoBnds) free(cLoBnds);	
		//if(cUpBnds) free(cUpBnds);
		//if(jacIndexVars) free(jacIndexVars);	
		//if(jacIndexCons) free(jacIndexCons); 
		//if(hessIndexRows) free(hessIndexRows); 
		//if(hessIndexCols) free(hessIndexCols);
		//free(lambda);
		KTR_free(&kc);
		//std::cout<<"Destructor of Knitro_context ends\n";
	}
	int System_potential_energy::callback(const int evalRequestCode, const int n, const int m, const int nnzJ, 
							const int nnzH,	const double * const x,	const double * const lambda, 
							double * const obj, double * const c, double * const objGrad, double * const jac,
							double * const hessian,	double * const hessVector, void * userParams)
	{
		System_potential_energy *pthis = static_cast< System_potential_energy* >(userParams);
		if (evalRequestCode == KTR_RC_EVALFC)
		{
			/* objective function */
			// x[2*n] for x-direction translation and x[2*n+1] for y-direction
			*obj = pthis->system_energy_at(x);
			pthis->constraint_at(x, c);
			return 0;
		}
		else if (evalRequestCode == KTR_RC_EVALGA)
		{
			pthis->energy_gradient_at(x, objGrad);
			pthis->constraint_grad_at(x, jac);
			return 0;
		}
		else 
		{
			printf("Wrong evalRequestCode in callback function.\n");
			return -1;
		}
	}
}